use crate::byte::*;
use super::error::*;

const LITERALS_LENGTH_DEFAULT_DISTRIBUTION:[i32;36] =
[4, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1,
 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 1, 1, 1, 1, 1,
 -1,-1,-1,-1];

const MATCH_LENGTHS_DEFAULT_DISTRIBUTION:[i32;53] =
 [1, 4, 3, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,
 -1,-1,-1,-1,-1];

 const OFFSET_CODES_DEFAULT_DISTRIBUTION:[i32;29] =
[1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
 1, 1, 1, 1, 1, 1, 1, 1,-1,-1,-1,-1,-1];

#[derive(Debug)]
pub struct FseDistribution {
    pub(crate) accuracy_log:u8,
    pub(crate) probabilities:Vec<i32>,
}

impl FseDistribution {
    pub fn predefined_literals_length_distribution() -> Self {
        Self { accuracy_log:6, probabilities:Vec::from(LITERALS_LENGTH_DEFAULT_DISTRIBUTION) }
    }

    pub fn predefined_match_length_distribution() -> Self {
        Self { accuracy_log:6, probabilities:Vec::from(MATCH_LENGTHS_DEFAULT_DISTRIBUTION) }
    }
    
    pub fn predefined_offset_codes_distribution() -> Self {
        Self { accuracy_log:5, probabilities:Vec::from(OFFSET_CODES_DEFAULT_DISTRIBUTION) }
    }

    //uncheck
    pub fn deserialize_from<R:ByteRead>(total_len:&mut u32,reader:&mut ByteReader<R>) -> FseResult<Self> {
        let mut bit_reader = BitReader::new(reader);
        let mut toal_bits_num = 4;
        let low4bit:u8 = bit_reader.read_bits(4)?;
        let accuracy_log = low4bit + 5;
        let mut cummulation = 1u32 << accuracy_log;
        let mut probabilities = Vec::new();

        while cummulation != 0 {
            let read_bits_num = u32::BITS - (cummulation + 1).leading_zeros();
            let half_base = 1 << (read_bits_num - 1);

            let lower_bit_sup = (half_base << 1) - 1 - cummulation - 1;

            let small_value = bit_reader.read_bits::<u32>(read_bits_num as usize - 1)?;


            let value = if small_value < lower_bit_sup {
                toal_bits_num += read_bits_num - 1;
                small_value
            } else {
                let high_bit = bit_reader.read_bits::<u8>(1)?;
                toal_bits_num += read_bits_num;
                if high_bit != 0 {  half_base + small_value - lower_bit_sup }
                else { small_value }
            };

            let probability = value as i32 - 1;
            cummulation -= probability.abs() as u32;
            probabilities.push(probability);

            if probability == 0 {
                let mut repeat_num = 0;
                loop {
                    let repeat_flag = bit_reader.read_bits::<u8>(2)?;
                    toal_bits_num += 2;
                    repeat_num += repeat_flag;
                    if repeat_flag != 3 { break; }
                }
                probabilities.append(&mut vec![0;repeat_num as usize]);
            }
        }

        toal_bits_num += bit_reader.read_remain_bits()? as u32;
        assert!(toal_bits_num % 8 == 0);
        *total_len -= toal_bits_num / 8;

        Ok(Self { accuracy_log, probabilities })
    }


}